#pragma once
#include "Common.hpp"
#include "Log.hpp"
#include <sys/epoll.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
namespace epoll_module
{
    using namespace LogModule;
    class epoller
    {
    public:
        epoller()
            :_epfd(-1)
        {}

        void init()
        {
            if(_epfd != -1)
            {
                LOG(LogLevel::WARNING) << "epoller already initialized";
                return; 
            }
            _epfd = epoll_create(256);
            if (_epfd == -1)
            {
                LOG(LogLevel::ERROR) << "epoll_create failed: " << strerror(errno);
                exit(EPOLL_CREATE_ERR);
            }
            LOG(LogLevel::INFO) << "epoll_create success" << " fd: " << _epfd;
        }


        int wait(epoll_event* events, int maxevents, int timeout = -1)
        {
            if(_epfd == -1)
            {
                LOG(LogLevel::ERROR) << "epoller not initialized";
                return -1;
            }
            int ret = epoll_wait(_epfd, events, maxevents, timeout);
            if(ret < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_wait failed: " << strerror(errno);
                return ret;
            }
            return ret;
        }
        void ctl(int fd, uint32_t events, int op)
        {
            if(_epfd == -1)
            {
                LOG(LogLevel::ERROR) << "epoller not initialized";
                return;
            }
            epoll_event event;
            event.data.fd = fd;
            event.events = events;
            int ret = epoll_ctl(_epfd, op, fd, &event);
            if(ret < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl add failed: " << strerror(errno);
                return;
            }  
            LOG(LogLevel::INFO) << "epoll_ctl add fd: " << fd << " events: " << events;
        }

        void modify(int fd, uint32_t events)
        {
            ctl(fd, events, EPOLL_CTL_MOD);
        }


        void add(int fd, uint32_t events)
        {
            ctl(fd, events, EPOLL_CTL_ADD);
        }


        void del(int fd)
        {
            ctl(fd, 0, EPOLL_CTL_DEL);
        }
        ~epoller()
        {
            if (_epfd != -1)
            {
                close(_epfd);
            }
        }
    private:
        int _epfd;
    };
}